/*
 * SlidingLayer.java
 *
 * Copyright (C) 2015 6 Wunderkinder GmbH.
 *
 * @author      Jose L Ugia - @Jl_Ugia
 * @author      Antonio Consuegra - @aconsuegra
 * @author      Cesar Valiente - @CesarValiente
 * @version     1.2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.wunderlist.slidinglayer;

import java.util.Random;

import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.components.*;
import ohos.agp.components.Component.EstimateSizeListener;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.ElementScatter;
import ohos.agp.render.Canvas;
import ohos.agp.utils.Point;
import ohos.app.Context;
import ohos.multimodalinput.event.ManipulationEvent;
import ohos.multimodalinput.event.MmiPoint;
import ohos.multimodalinput.event.TouchEvent;
import ohos.utils.PacMap;


public class SlidingLayer extends StackLayout implements Component.TouchEventListener,
    EstimateSizeListener, ComponentContainer.ArrangeListener, Component.DrawTask,
    ComponentTreeObserver.ScrollChangedListener {
  private static final String STATE_KEY = "state";

  /**
   * Special value for the position of the layer. STICK_TO_RIGHT means that
   * the view shall be attached to the right side of the screen, and come from
   * there into the viewable area.
   */
  public static final int STICK_TO_RIGHT = -1;

  /**
   * Special value for the position of the layer. STICK_TO_LEFT means that the
   * view shall be attached to the left side of the screen, and come from
   * there into the viewable area.
   */
  public static final int STICK_TO_LEFT = -2;

  /**
   * Special value for the position of the layer.
   * STICK_TO_TOP means that the view will stay attached to the top
   * part of the screen, and come from there into the viewable area.
   */
  public static final int STICK_TO_TOP = -3;

  /**
   * Special value for the position of the layer.
   * STICK_TO_BOTTOM means that the view will stay attached to the
   * bottom part of the screen, and come from there into the viewable area.
   */
  public static final int STICK_TO_BOTTOM = -4;
  /**
   * Special animation effect when the layer appears and returns.
   */
  public static final int Transform_TO_NONE = 0;
  public static final int Transform_TO_ALPHA = 1;
  public static final int Transform_TO_ROTATION = 2;
  public static final int Transform_TO_SLIDE = 3;
  private int transform;

  private static final int HORIZONTAL = 0;
  private static final int VERTICAL = 1;

  private static final int HIGH_VELOCITY = 9000;
  private static final int MAX_SCROLLING_DURATION = 600; // in ms
  private static final int MIN_DISTANCE_FOR_FLING = 10; // in dip

  /**
   * Sentinel value for no current active pointer. Used by {@link #mActivePointerId}.
   */
  private static final int INVALID_VALUE = -1;
  protected int mActivePointerId = INVALID_VALUE;
  protected VelocityDetector mVelocityTracker;
  protected int mMaximumVelocity;
  private Random mRandom;
  protected PacMap mState;
  private ScrollHelper scrollHelper;
  private int mShadowSize;
  private Element mShadowDrawable;
  private boolean mForceLayout;
  /**
   * The size of the panel that sticks out when closed
   */
  private int mOffsetDistance;

  private boolean mDrawingCacheEnabled;
  private int mScreenSide;

  /**
   * If the user taps the layer then we will switch state it if enabled.
   */
  private boolean changeStateOnTap = true;

  /**
   * The size of the panel in preview mode
   */
  private int mPreviewOffsetDistance = INVALID_VALUE;

  private boolean mEnabled = true;
  private boolean mSlidingFromShadowEnabled = true;
  private boolean mIsDragging;
  private boolean mIsUnableToDrag;
  private int mTouchSlop;

  private float mLastX = INVALID_VALUE;
  private float mLastY = INVALID_VALUE;

  private float mInitialX = INVALID_VALUE;
  private float mInitialY = INVALID_VALUE;
  private float mInitialRawX = INVALID_VALUE;
  private float mInitialRawY = INVALID_VALUE;

  /**
   * Flags to determine the state of the layer
   */
  public static final int STATE_CLOSED = 0;
  private static final int STATE_PREVIEW = 1;
  private static final int STATE_OPENED = 2;

  private int mCurrentState;

  private boolean mScrolling;

  private OnInteractListener mOnInteractListener;

  /**
   * Optional callback to notify client when scroll position has changed
   */
  private OnScrollListener mOnScrollListener;

  private int mMinimumVelocity;
  private int mFlingDistance;

  private LayerTransformer mLayerTransformer;

  private DependentLayout depend;
  private AnimatorProperty animatorProperty;
  private AnimatorProperty animatorPropertyTwo;
  private AnimatorProperty animatorPropertyOne;
  private int changeOffset;
  private int bottomOffset;
  private boolean offsetEnable;
  private boolean previewEnable;
  private boolean drag;


  private Image imageClose;
  private Point point;
  private final ThreadLocal<Point> componentPo = new ThreadLocal<Point>();
  private boolean skip;
  private int heightMax;
  private int widthMax;
  private float startX;
  private float startY;
  private int angle;
  private AnimatorProperty closeAnimator;
  private AnimatorGroup animatorGroup;
  private AnimatorGroup.Builder builder;


  public SlidingLayer(Context context) {
    this(context, null);

  }

  public SlidingLayer(Context context, AttrSet attrs) {
    this(context, attrs, "");
    setEstimateSizeListener(this);

  }

  public SlidingLayer(Context context, AttrSet attrs, String defStyle) {
    super(context, attrs, defStyle);
    init();
  }

  private void init() {
    mCurrentState = STATE_CLOSED;
    angle = 0;
    closeAnimator = new AnimatorProperty();
    animatorGroup = new AnimatorGroup();
    builder = animatorGroup.build();
  }

  /**
   * Put the component into the animation
   */
  public void addDepend(DependentLayout dependentLayout, Image image) {
    this.depend = dependentLayout;
    imageClose = image;
    animatorProperty = new AnimatorProperty();
    animatorProperty.setTarget(depend);
    animatorPropertyOne = new AnimatorProperty();
    animatorPropertyOne.setTarget(depend);
    animatorPropertyTwo = new AnimatorProperty();
    animatorPropertyTwo.setTarget(depend);
    imageListener();
  }

  /**
   * Component closed
   */
  public void imageListener() {
    imageClose.setTouchEventListener(new Component.TouchEventListener() {
      @Override
      public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        closeAnimator.setTarget(imageClose);
        switch (touchEvent.getAction()) {
          case TouchEvent.PRIMARY_POINT_DOWN:
            closeAnimator
                .scaleYFrom(1.0f).scaleY(0.9f)
                .scaleXFrom(1.0f).scaleX(0.9f);
            closeAnimator.start();
            break;
          case TouchEvent.PRIMARY_POINT_UP:
            closeAnimator
                .scaleYFrom(0.9f).scaleY(1.0f)
                .scaleXFrom(0.9f).scaleX(1.0f);
            closeAnimator.start();
            closeLayer(true);
            skip = false;
            break;
          default:
            break;
        }
        return true;
      }
    });
  }

  /**
   * Drag and click function of the side slide component
   */
  public void dependEvent() {
    setAngle();
    depend.setDraggedListener(Component.DRAG_HORIZONTAL_VERTICAL, new Component.DraggedListener() {
      float endX;
      float endY;
      float distance;
      float change = 0;
      int width = depend.getWidth();
      int height = depend.getHeight();


      @Override
      public boolean onDragPreAccept(Component component, int dragDirection) {
        return true;
      }

      @Override
      public void onDragDown(Component component, DragInfo dragInfo) {
        skip = true;
        startX = component.getContentPositionX();
        startY = component.getContentPositionY();

      }

      @Override
      public void onDragStart(Component component, DragInfo dragInfo) {
        point = dragInfo.startPoint;
        startX = component.getContentPositionX();
        startY = component.getContentPositionY();
        componentPo.set(new Point(startX, startY));
      }

      @Override
      public void onDragUpdate(Component component, DragInfo dragInfo) {
        float heightPixels = heightMax;
        float widthPixels = widthMax;

        float xOffset = dragInfo.updatePoint.getPointX() - point.getPointX();
        float yOffset = dragInfo.updatePoint.getPointY() - point.getPointY();
        boolean finish = true;
        switch (mScreenSide) {
          case STICK_TO_RIGHT:
            yOffset = 0;
            finish = startX == widthPixels - width && xOffset < 0 ? false : true;
            break;
          case STICK_TO_LEFT:
            yOffset = 0;
            finish = startX == 0 && xOffset > 0 ? false : true;
            break;
          case STICK_TO_TOP:
            xOffset = 0;
            finish = startY >= -0.3f * height && yOffset > 0 ? false : true;
            break;
          case STICK_TO_BOTTOM:
            xOffset = 0;
            finish = startY == 0 && yOffset < 0 ? false : true;
            break;
          default:
            break;
        }
        if (finish) {
          component.setContentPosition(componentPo.get().getPointX() + xOffset,
              componentPo.get().getPointY() + yOffset);
          endX = component.getContentPositionX();
          endY = component.getContentPositionY();
          if (xOffset != 0) {
            distance = endX - startX;
          } else {
            distance = endY - startY;
          }

          if (distance > 0) {
            change = distance;
          } else {
            change = -distance;
          }
          float alphaX = change / component.getWidth();
          float alphaY = change / component.getHeight();
          switch (transform) {
            case Transform_TO_ALPHA:
              switch (mScreenSide) {
                case STICK_TO_RIGHT:
                  if (distance > 0) {
                    component.setAlpha(1 - alphaX);
                  } else {
                    component.setAlpha(alphaX);
                  }
                  break;
                case STICK_TO_LEFT:
                  if (distance > 0) {
                    component.setAlpha(alphaX);
                  } else {
                    component.setAlpha(1 - alphaX);
                  }
                  break;
                case STICK_TO_TOP:
                  if (distance > 0) {
                    component.setAlpha(alphaY);
                  } else {
                    component.setAlpha(1 - alphaY);
                  }
                  break;
                case STICK_TO_BOTTOM:
                  if (distance > 0) {
                    component.setAlpha(1 - alphaY);
                  } else {
                    component.setAlpha(alphaY);
                  }
                  break;
                default:
                  break;
              }
              break;
            case Transform_TO_ROTATION:
              switch (mScreenSide) {
                case STICK_TO_RIGHT:
                  if (distance > 0) {
                    component.setRotation(5 * alphaX);
                  } else {
                    component.setRotation(5 * (1 - alphaX));
                  }
                  break;
                case STICK_TO_LEFT:
                  if (distance > 0) {
                    component.setRotation(-5 * (1 - alphaX));
                  } else {
                    component.setRotation(-5 * alphaX);
                  }
                  break;
                case STICK_TO_TOP:


                  if (distance > 0) {
                    component.setRotation(-5 * (1 - alphaY));
                  } else {
                    component.setRotation(-5 * alphaY);
                  }
                  break;
                case STICK_TO_BOTTOM:
                  if (distance > 0) {
                    component.setRotation(5 * alphaY);
                  } else {
                    component.setRotation(5 * (1 - alphaY));
                  }
                  break;
                default:
                  break;
              }
              break;
            case Transform_TO_SLIDE:
              switch (mScreenSide) {
                case STICK_TO_RIGHT:
                  if (distance > 0) {
                    component.setScale(1 - alphaX * 0.15f, 1 - 0.1f * alphaX);
                  } else {
                    component.setScale(0.85f + alphaX * 0.15f, 0.9f + 0.1f * alphaX);
                  }
                  break;
                case STICK_TO_LEFT:
                  if (distance > 0) {
                    component.setScale(0.85f + alphaX * 0.15f, 0.9f + 0.1f * alphaX);
                  } else {
                    component.setScale(1 - alphaX * 0.15f, 1 - 0.1f * alphaX);
                  }
                  break;
                case STICK_TO_TOP:
                  if (distance > 0) {
                    component.setScale(0.85f + alphaY * 0.15f, 0.9f + 0.1f * alphaY);
                  } else {
                    component.setScale(1 - alphaY * 0.15f, 1 - 0.1f * alphaY);
                  }
                  break;
                case STICK_TO_BOTTOM:
                  if (distance > 0) {
                    component.setScale(1 - alphaY * 0.15f, 1 - 0.1f * alphaY);
                  } else {
                    component.setScale(0.85f + alphaY * 0.15f, 0.9f + 0.1f * alphaY);
                  }
                  break;
                default:
                  break;
              }
              break;
            default:

              break;
          }

          componentPo.set(new Point(component.getContentPositionX(),
              component.getContentPositionY()));

        }

      }

      @Override
      public void onDragEnd(Component component, DragInfo dragInfo) {
        drag = true;
        switch (mScreenSide) {
          case STICK_TO_RIGHT:
            if (distance < 0) {
              if (change > width / 3) {
                openLayer(true);
              } else {
                repeat(width, height);
              }
            } else if (distance > 0) {
              if (change > width / 3) {
                closeLayer(true);
              } else {
                if (startX > widthMax - width) {
                  closeLayer(true);
                } else {
                  repeat(width, height);
                }
              }
            }
            break;
          case STICK_TO_LEFT:
            if (distance < 0) {
              if (change > width / 3) {
                closeLayer(true);
              } else {
                if (startX < 0) {
                  closeLayer(true);
                } else {
                  repeat(width, height);
                }
              }
            } else if (distance > 0) {
              if (change > width / 3) {
                openLayer(true);
              } else {
                repeat(width, height);
              }
            }
            break;
          case STICK_TO_TOP:
            if (distance < 0) {
              if (change > height / 4) {
                closeLayer(true);
              } else {
                if (startY < -0.3 * height) {
                  closeLayer(true);
                } else {
                  repeat(width, height);
                }
              }
            } else if (distance > 0) {
              openLayer(true);
            }
            break;
          case STICK_TO_BOTTOM:
            if (distance < 0) {
              if (change > height / 3) {
                openLayer(true);
              } else {
                repeat(width, height);
              }
            } else if (distance > 0) {
              if (change > height / 3) {
                closeLayer(true);
              } else {
                if (startY > 0) {
                  closeLayer(true);
                } else {
                  repeat(width, height);
                }
              }
            }
            break;
          default:
            break;
        }
        drag = false;
      }

      @Override
      public void onDragCancel(Component component, DragInfo dragInfo) {
        if (skip) {
          repeat(width, height);
        }
      }
    });
  }

  /**
   * Component drag and click corresponding function and state change
   *
   * @param width
   * @param height
   */
  private void repeat(int width, int height) {
    switch (mCurrentState) {
      case STATE_OPENED:
        if (previewEnable) {
          clickReturn(width, height);
          mCurrentState = STATE_PREVIEW;
        } else {
          closeLayer(true);
        }
        break;
      case STATE_CLOSED:
        if (previewEnable) {
          clickOpen(width, height);
          mCurrentState = STATE_PREVIEW;
        } else {
          openLayer(true);
        }
        break;
      default:
        previewOpen(width, height);
        mCurrentState = STATE_OPENED;
        break;
    }
  }

  /**
   * Preview the OPEN state under conditions
   *
   * @param width
   * @param height
   */
  private void previewOpen(int width, int height) {
    switch (mScreenSide) {
      case STICK_TO_RIGHT:
        animatorProperty
            .moveFromX(startX)
            .moveToX(widthMax - width);
        break;
      case STICK_TO_LEFT:
        animatorProperty
            .moveFromX(startX)
            .moveToX(0);
        break;
      case STICK_TO_TOP:
        animatorProperty
            .moveFromY(startY)
            .moveToY(-height * 0.3f);
        break;
      case STICK_TO_BOTTOM:
        animatorProperty
            .moveFromY(startY)
            .moveToY(0);
        break;
      default:
        break;
    }
    animatorProperty
        .setDuration(200)
        .start();
  }

  /**
   * Preview the OPEN state under conditions
   *
   * @param width
   * @param height
   */
  private void clickOpen(int width, int height) {
    switch (mScreenSide) {
      case STICK_TO_RIGHT:
        animatorProperty
            .moveFromX(startX)
            .moveToX(widthMax - mPreviewOffsetDistance);
        break;
      case STICK_TO_LEFT:
        animatorProperty
            .moveFromX(startX)
            .moveToX(-width + mPreviewOffsetDistance);
        break;
      case STICK_TO_TOP:
        animatorProperty
            .moveFromY(startY)
            .moveToY(-height + mPreviewOffsetDistance);
        break;
      case STICK_TO_BOTTOM:
        animatorProperty
            .moveFromY(startY)
            .moveToY(height - mPreviewOffsetDistance);
        break;
      default:
        break;
    }
    animatorProperty
        .alpha(1)
        .rotate(0)
        .scaleX(1)
        .scaleY(1)
        .setDuration(200)
        .start();

  }

  /**
   * Preview the CLOSE state of the condition
   *
   * @param width
   * @param height
   */
  private void clickReturn(int width, int height) {

    switch (mScreenSide) {
      case STICK_TO_RIGHT:
        animatorProperty
            .moveFromX(startX)
            .moveToX(widthMax - mPreviewOffsetDistance);
        break;
      case STICK_TO_LEFT:
        animatorProperty
            .moveFromX(startX)
            .moveToX(-width + mPreviewOffsetDistance);
        break;
      case STICK_TO_TOP:
        animatorProperty
            .moveFromY(startY)
            .moveToY(-height + mPreviewOffsetDistance);
        break;
      case STICK_TO_BOTTOM:
        animatorProperty
            .moveFromY(startY)
            .moveToY(height - mPreviewOffsetDistance);
        break;
      default:
        break;
    }
    animatorProperty
        .alpha(1)
        .rotate(0)
        .scaleX(1)
        .scaleY(1)
        .setDuration(200)
        .start();


  }


  public void addOffset(int offSet, boolean enable) {
    changeOffset = offSet;
    offsetEnable = enable;
  }

  public void setNature(int height, int width) {
    this.heightMax = height;
    this.widthMax = width;
  }


  /**
   * Method exposing the state of the panel
   *
   * @return returns the state of the panel (@link STATE_OPENED, STATE_CLOSED or STATE_PREVIEW).
   * Please note
   * that if the panel was opened with smooth animation this method is not guaranteed to return
   * its final value until the panel has reached its final position.
   */
  private int getCurrentState() {
    return mCurrentState;
  }


  public boolean isClosed() {
    return mCurrentState == STATE_CLOSED;
  }

  public void openLayer(final boolean smoothAnimation) {
    setLayerState(STATE_OPENED, smoothAnimation);
  }

  public void openPreview(final boolean smoothAnimation) {
    if (mPreviewOffsetDistance == INVALID_VALUE) {
      throw new IllegalStateException(
          "A value offset for the preview has to be specified in order to open "
              + "the layer in preview mode. "
              + "Use setPreviewOffsetDistance or set its associated XML property ");
    }
    setLayerState(STATE_PREVIEW, smoothAnimation);
  }

  public void closeLayer(final boolean smoothAnimation) {
    setLayerState(STATE_CLOSED, smoothAnimation);
  }

  private void setLayerState(final int state, final boolean smoothAnimation) {
    setLayerState(state, smoothAnimation, false);
  }

  private void setLayerState(final int state, final boolean smoothAnimation, boolean force) {
    setLayerState(state, smoothAnimation, force, 0, 0);
  }


  /**
   * Sets the listener to be invoked after a switch change
   * {@link OnInteractListener}.
   *
   * @param listener Listener to set
   */
  public void setOnInteractListener(OnInteractListener listener) {
    mOnInteractListener = listener;
  }

  /**
   * Sets the listener to be invoked when the layer is being scrolled
   * {@link OnScrollListener}.
   *
   * @param listener Listener to set
   */
  public void setOnScrollListener(OnScrollListener listener) {
    mOnScrollListener = listener;
  }

  /**
   * Sets the transformer to use when the layer is being scrolled
   * {@link LayerTransformer}.
   *
   * @param layerTransformer Transformer to adopt
   */
  public void setLayerTransformer(LayerTransformer layerTransformer) {
    mLayerTransformer = layerTransformer;
  }

  /**
   * Sets the animation used when the layer state changes
   */
  public void setTransformer(int transformer) {
    this.transform = transformer;

  }

  /**
   * Sets the shadow of the size which will be included within the view by
   * * using padding since it's on the left of the view in this case
   */
  public void setShadowSize(Text text, int size, int width, int height) {
    ComponentContainer.LayoutConfig layoutConfig = text.getLayoutConfig();
    switch (mScreenSide) {
      case STICK_TO_RIGHT:
        layoutConfig.height = ComponentContainer.LayoutConfig.MATCH_PARENT;
        layoutConfig.width = size;
        text.setLayoutConfig(layoutConfig);
        break;
      case STICK_TO_LEFT:
        layoutConfig.height = ComponentContainer.LayoutConfig.MATCH_PARENT;
        layoutConfig.width = size;
        text.setLayoutConfig(layoutConfig);
        text.setMarginLeft(width - size);
        break;
      case STICK_TO_BOTTOM:
        layoutConfig.height = size;
        layoutConfig.width = ComponentContainer.LayoutConfig.MATCH_PARENT;
        text.setLayoutConfig(layoutConfig);
        break;
      default:
        layoutConfig.height = size;
        layoutConfig.width = ComponentContainer.LayoutConfig.MATCH_PARENT;
        text.setLayoutConfig(layoutConfig);
        text.setMarginTop(height - size);
        break;
    }

  }

  /**
   * Return the current size of the shadow.
   *
   * @return The size of the shadow in pixels
   */
  public int getShadowSize() {
    return mShadowSize;
  }

  /**
   * Sets a drawable that will be used to create the shadow for the layer.
   *
   * @param d Drawable append as a shadow
   */
  public void setShadowDrawable(final Element d) {
    mShadowDrawable = d;
  }

  /**
   * Sets a drawable resource that will be used to create the shadow for the
   * layer.
   *
   * @param resId Resource ID of a drawable
   */
  public void setShadowDrawable(int resId) {
    Element a = ElementScatter.getInstance(getContext()).parse(INVALID_VALUE);
    setShadowDrawable(a);
  }


  /**
   * Sets the offset distance of the panel. How much sticks out when off screen.
   *
   * @param offsetDistance Size of the offset in pixels
   * @see #getOffsetDistance()
   */
  public void setOffsetDistance(int offsetDistance) {
    mOffsetDistance = offsetDistance;
    checkPreviewModeConsistency();
  }

  /**
   * @return returns the number of pixels that are visible when the panel is closed
   */
  public int getOffsetDistance() {
    return mOffsetDistance;
  }

  /**
   * Sets the offset distance of the preview panel by using a dimension resource.
   *
   * @param resId The dimension resource id to be set as the size of the preview mode.
   */
  public void setPreviewOffsetDistanceRes(int resId) {

  }

  /**
   * Sets the size of the panel when in preview mode.
   *
   * @param previewOffsetDistance Size of the offset in pixels
   * @see #getOffsetDistance()
   */
  public void setPreviewOffsetDistance(int previewOffsetDistance,
                                       boolean enable, int bottomHeight) {
    mPreviewOffsetDistance = previewOffsetDistance;
    previewEnable = enable;
    bottomOffset = bottomHeight;
  }

  private void checkPreviewModeConsistency() {
    if (isPreviewModeEnabled() && mOffsetDistance > mPreviewOffsetDistance) {
      throw new IllegalStateException(
          "The showing offset of the layer can never be greater than the "
              + "offset dimension of the preview mode");
    }
  }

  /**
   * @return true if the preview mode is enabled
   */
  private boolean isPreviewModeEnabled() {
    return mPreviewOffsetDistance != INVALID_VALUE;
  }


  public boolean isSlidingEnabled() {
    return mEnabled;
  }

  public void setSlidingEnabled(boolean _enabled) {
    mEnabled = _enabled;
  }

  public boolean isSlidingFromShadowEnabled() {
    return mSlidingFromShadowEnabled;
  }

  public void setSlidingFromShadowEnabled(boolean _slidingShadow) {
    mSlidingFromShadowEnabled = _slidingShadow;
  }


  private MmiPoint getViewX(ManipulationEvent event) {
    return event.getPointerScreenPosition(536);
  }

  private MmiPoint getViewY(ManipulationEvent event) {
    return event.getPointerScreenPosition(905);
  }


  @Override
  public boolean onTouchEvent(Component component, TouchEvent ev) {
    ManipulationEvent event = ev;

    if (ev.getAction() == TouchEvent.PRIMARY_POINT_DOWN) {
      return false;
    }

    if (!mEnabled || !mIsDragging && !touchPointIsWithinBounds(mInitialX, mInitialY)) {
      return false;
    }

    if (mVelocityTracker == null) {
      mVelocityTracker = VelocityDetector.obtainInstance();
    }
    mVelocityTracker.addEvent(ev);

    final int action = ev.getAction();

    switch (action) {
      case TouchEvent.PRIMARY_POINT_DOWN: {
        completeScroll();
        mLastX = mInitialRawX = getViewX(ev).getX();
        mLastY = mInitialRawY = getViewY(ev).getY();
        mActivePointerId = ev.getPointerId(0);
        break;
      }

      case TouchEvent.POINT_MOVE: {
        ManipulationEvent a = ev;
        if (!touchPointIsWithinBounds(ev.getIndex(), ev.getIndex(), false)) {
          return false;
        }

        final float x = getViewX(ev).getX();
        final float y = getViewY(ev).getY();

        final float deltaX = mLastX - x;
        final float deltaY = mLastY - y;

        mLastX = x;
        mLastY = y;

        if (!mIsDragging) {

          final float xDiff = Math.abs(x - mInitialRawX);
          final float yDiff = Math.abs(y - mInitialRawY);

          final boolean validHorizontalDrag = xDiff > mTouchSlop && xDiff > yDiff;
          final boolean validVerticalDrag = yDiff > mTouchSlop && yDiff > xDiff;

          if (validHorizontalDrag || validVerticalDrag) {
            mIsDragging = true;
          }
        }

        if (mIsDragging) {

          final float oldScrollX = getScrollValue(AXIS_X);
          final float oldScrollY = getScrollValue(AXIS_Y);
          float scrollX = oldScrollX + deltaX;
          float scrollY = oldScrollY + deltaY;
          final float leftBound;
          final float rightBound;
          final float bottomBound;
          final float topBound;
          switch (mScreenSide) {
            case STICK_TO_LEFT:
              topBound = bottomBound = rightBound = 0;
              leftBound = getWidth();
              break;
            case STICK_TO_RIGHT:
              rightBound = -getWidth();
              topBound = bottomBound = leftBound = 0;
              break;
            case STICK_TO_TOP:
              topBound = getHeight();
              bottomBound = rightBound = leftBound = 0;
              break;
            case STICK_TO_BOTTOM:
              bottomBound = -getHeight();
              topBound = rightBound = leftBound = 0;
              break;
            default:
              topBound = bottomBound = rightBound = leftBound = 0;
              break;
          }

          if (scrollX > leftBound) {
            scrollX = leftBound;
          } else if (scrollX < rightBound) {
            scrollX = rightBound;
          }
          if (scrollY > topBound) {
            scrollY = topBound;
          } else if (scrollY < bottomBound) {
            scrollY = bottomBound;
          }

          // Keep the precision
          mLastX += scrollX - (int) scrollX;
          mLastY += scrollY - (int) scrollY;

          scrollToAndNotify((int) scrollX, (int) scrollY);
        }
        break;
      }

      case TouchEvent.PRIMARY_POINT_UP: {

        if (mIsDragging) {
          final VelocityDetector velocityTracker = mVelocityTracker;
          velocityTracker.calculateCurrentVelocity(1000);
          final int initialVelocityX = (int) velocityTracker.getHorizontalVelocity();
          final int initialVelocityY = (int) velocityTracker.getVerticalVelocity();
          final int scrollX = getScrollValue(AXIS_X);
          final int scrollY = getScrollValue(AXIS_Y);

          final float x = getViewX(ev).getX();
          final float y = getViewY(ev).getY();

          int nextState = determineNextStateForDrag(scrollX, scrollY,
              initialVelocityX, initialVelocityY,
              (int) mInitialRawX, (int) mInitialRawY, (int) x, (int) y);
          setLayerState(nextState, true, true,
              initialVelocityX, initialVelocityY);

          mActivePointerId = INVALID_VALUE;
          endDrag();

        } else if (changeStateOnTap) {
          int nextState = determineNextStateAfterTap();
          setLayerState(nextState, true, true);
        }
        break;
      }

      case TouchEvent.CANCEL:
        if (mIsDragging) {
          setLayerState(mCurrentState, true, true);
          mActivePointerId = INVALID_VALUE;
          endDrag();
        }
        break;
      default:
        break;

    }

    return true;
  }

  /**
   * Checks if it's allowed to slide from the given position.
   *
   * @param touchX where the touch event started
   * @param touchY where the touch event started.
   * @return true if you can drag this view, false otherwise
   */
  private boolean touchPointIsWithinBounds(final float touchX, final float touchY) {
    return touchPointIsWithinBounds(touchX, touchY, true);
  }

  private boolean touchPointIsWithinBounds(final float touchX,
                                           final float touchY, boolean withinLayer) {

    int scroll = 0;
    float touch;

    if (allowedDirection() == HORIZONTAL) {
      if (withinLayer) {
        scroll = getScrollValue(AXIS_X);
      }
      touch = touchX;
    } else {
      if (withinLayer) {
        scroll = getScrollValue(AXIS_Y);
      }
      touch = touchY;
    }

    switch (mScreenSide) {
      case STICK_TO_RIGHT:
      case STICK_TO_BOTTOM:
        return touch >= -scroll;
      case STICK_TO_LEFT:
        return touch <= getWidth() - scroll;
      case STICK_TO_TOP:
        return touch <= getHeight() - scroll;
      default:
        throw new IllegalStateException(
            "The layer has to be stuck to one of the sides of the screen. "
                + "Current value is: " + mScreenSide);
    }
  }

  protected boolean canScroll(Component v, boolean checkV, int dx, int dy, int x, int y) {

    if (v instanceof ComponentContainer) {
      final ComponentContainer group = (ComponentContainer) v;
      final int scrollX = v.getScrollValue(AXIS_X);
      final int scrollY = v.getScrollValue(AXIS_Y);

      final int count = group.getChildCount();
      // Count backwards - let topmost views consume scroll distance first.
      for (int i = count - 1; i >= 0; i--) {
        // TODO: Add versioned support here for transformed views.
        // This will not work for transformed views in Honeycomb+
        final Component child = group.getComponentAt(i);
        if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight()
            && y + scrollY >= child.getTop() && y + scrollY < child.getBottom()
            && canScroll(child, true, dx, dy, x + scrollX - child.getLeft(),
            y + scrollY - child.getTop())) {
          return true;
        }
      }
    }

    return checkV && (
        (allowedDirection() == HORIZONTAL && v.canScroll(-dx)
            || allowedDirection() == VERTICAL && v.canScroll(-dy)));
  }

  /**
   * Based on the position and velocity of the layer we calculate what the next state should be.
   *
   * @return the state of the panel (@link STATE_OPENED, STATE_CLOSED or STATE_PREVIEW).
   */
  private int determineNextStateForDrag(final int scrollX, final int scrollY, final int velocityX,
                                        final int velocityY, final int initialX, final int initialY,
                                        final int currentX, final int currentY) {

    int panelOffset;
    int panelSize;
    int relativeVelocity;
    int absoluteDelta;

    if (allowedDirection() == HORIZONTAL) {
      panelSize = getWidth();
      panelOffset = Math.abs(panelSize - Math.abs(scrollX));
      absoluteDelta = Math.abs(currentX - initialX);
      relativeVelocity = velocityX * (mScreenSide == STICK_TO_LEFT ? 1 : -1);
    } else {
      panelSize = getHeight();
      panelOffset = Math.abs(panelSize - Math.abs(scrollY));
      absoluteDelta = Math.abs(currentY - initialY);
      relativeVelocity = velocityY * (mScreenSide == STICK_TO_TOP ? 1 : -1);
    }

    final int absoluteVelocity = Math.abs(relativeVelocity);
    final boolean isOverThreshold = absoluteDelta > mFlingDistance
        && absoluteVelocity > mMinimumVelocity;

    if (isOverThreshold) {

      if (relativeVelocity > 0) {
        return STATE_OPENED;
      } else {

        boolean goesToPreview = isPreviewModeEnabled()
            && panelOffset > mPreviewOffsetDistance
            && absoluteVelocity < HIGH_VELOCITY;

        if (goesToPreview) {
          return STATE_PREVIEW;
        } else {
          return STATE_CLOSED;
        }
      }

    } else {

      int openedThreshold = (panelSize + (isPreviewModeEnabled() ? mPreviewOffsetDistance : 0)) / 2;

      if (panelOffset > openedThreshold) {
        return STATE_OPENED;
      } else if (isPreviewModeEnabled() && panelOffset > mPreviewOffsetDistance / 2) {
        return STATE_PREVIEW;
      } else {
        return STATE_CLOSED;
      }
    }
  }

  /**
   * Based on the current state of the panel, this method returns the next state after tapping.
   *
   * @return the state of the panel (@link STATE_OPENED, STATE_CLOSED or STATE_PREVIEW).
   */
  private int determineNextStateAfterTap() {

    switch (mCurrentState) {
      case STATE_CLOSED:
        return isPreviewModeEnabled() ? STATE_PREVIEW : STATE_OPENED;
      case STATE_PREVIEW:
        return STATE_OPENED;
      case STATE_OPENED:
        return isPreviewModeEnabled() ? STATE_PREVIEW : STATE_CLOSED;
      default:
        break;
    }

    return STATE_CLOSED;
  }


  // We want the duration of the page snap animation to be influenced by the
  // distance that
  // the screen has to travel, however, we don't want this duration to be
  // effected in a
  // purely linear fashion. Instead, we use this method to moderate the effect
  // that the distance
  // of travel has on the overall snap duration.
  float distanceInfluenceForSnapDuration(float f) {
    f -= 0.5f; // center the values about 0.
    f *= 0.3f * Math.PI / 2.0f;
    return (float) Math.sin(f);
  }

  private void endDrag() {
    mIsDragging = false;
    mIsUnableToDrag = false;

    if (mVelocityTracker != null) {
      mVelocityTracker.clear();
      mVelocityTracker = null;
    }
  }


  private void onSecondaryPointerUp(TouchEvent ev) {
    final int pointerIndex = ev.getIndex();
    final int pointerId = ev.getPointerId(pointerIndex);
  }

  private void completeScroll() {

    boolean needPopulate = mScrolling;
    if (needPopulate) {
      // Done with scroll, no longer want to cache view drawing.
      scrollHelper.abortAnimation();
      int oldX = getScrollValue(AXIS_X);
      int oldY = getScrollValue(AXIS_Y);
      int x = scrollHelper.getCurrValue(AXIS_X);
      int y = scrollHelper.getCurrValue(AXIS_Y);
      if (oldX != x || oldY != y) {
        scrollToAndNotify(x, y);
      }
      if (mOnInteractListener != null) {
        notifyActionFinished();
      }
    }
    mScrolling = false;
  }

  private void scrollToAndNotify(int x, int y) {

    scrollTo(x, y);

    if (mOnScrollListener == null && mLayerTransformer == null) {
      return;
    }

    int scroll;
    if (allowedDirection() == VERTICAL) {
      scroll = getHeight() - Math.abs(y);
    } else {
      scroll = getWidth() - Math.abs(x);
    }

    if (mOnScrollListener != null) {
      mOnScrollListener.onScroll(Math.abs(scroll));
    }

    if (mLayerTransformer != null) {

      int absoluteScroll = Math.abs(scroll);
      int layerSize = allowedDirection() == HORIZONTAL ? getEstimatedWidth() : getEstimatedHeight();

      float layerProgress = (float) absoluteScroll / layerSize;
      float previewProgress = mPreviewOffsetDistance > 0
          ? Math.min(1, (float) absoluteScroll / mPreviewOffsetDistance) :
          0;

      mLayerTransformer.internalTransform(this, previewProgress, layerProgress, mScreenSide);
    }
  }

  /**
   * Sets the default location where the SlidingLayer will appear
   *
   * @param screenSide The location where the Sliding layer will appear. Possible values are
   *                   {@link #STICK_TO_BOTTOM}, {@link #STICK_TO_LEFT}
   *                   {@link #STICK_TO_RIGHT}, {@link #STICK_TO_TOP}
   */
  public void setStickTo(int screenSide) {
    mForceLayout = true;
    mScreenSide = screenSide;
  }

  private int allowedDirection() {

    if (mScreenSide == STICK_TO_TOP || mScreenSide == STICK_TO_BOTTOM) {
      return VERTICAL;
    } else if (mScreenSide == STICK_TO_LEFT || mScreenSide == STICK_TO_RIGHT) {
      return HORIZONTAL;
    }
    throw new IllegalStateException("The screen side of the layer is illegal");
  }

  /**
   * Sets the behavior when tapping the sliding layer
   */
  public void setChangeStateOnTap(boolean changeStateOnTap) {
    this.changeStateOnTap = changeStateOnTap;
  }

  @Override
  public boolean onEstimateSize(int widthMeasureSpec, int heightMeasureSpec) {
    setEstimatedSize(widthMeasureSpec, heightMeasureSpec);

    if (mLayerTransformer != null) {
      mLayerTransformer.onMeasure(this, mScreenSide);
    }

    return false;
  }

  @Override
  public boolean onArrange(int w, int h, int oldw, int oldh) {

    boolean scrollMustChange = false;
    if (allowedDirection() == VERTICAL) {
      if (h != oldh) {
        scrollMustChange = true;
      }
    } else if (w != oldw) {
      scrollMustChange = true;
    }

    if (scrollMustChange) {
      completeScroll();
      int[] pos = getDestScrollPosForState(mCurrentState);
      scrollTo(pos[0], pos[1]);
    }
    if (mForceLayout) {
      mForceLayout = false;
      adjustLayoutParams();

      if (mScreenSide == STICK_TO_RIGHT) {
        setPadding(getPaddingLeft() + mShadowSize,
            getPaddingTop(), getPaddingRight(), getPaddingBottom());
      } else if (mScreenSide == STICK_TO_BOTTOM) {
        setPadding(getPaddingLeft(), getPaddingTop() + mShadowSize,
            getPaddingRight(), getPaddingBottom());
      } else if (mScreenSide == STICK_TO_LEFT) {
        setPadding(getPaddingLeft(), getPaddingTop(),
            getPaddingRight() + mShadowSize, getPaddingBottom());
      } else if (mScreenSide == STICK_TO_TOP) {
        setPadding(getPaddingLeft(), getPaddingTop(),
            getPaddingRight(), getPaddingBottom() + mShadowSize);
      }
    }
    return false;
  }


  @Override
  public void onDraw(Component component, Canvas canvas) {

    if (mShadowSize > 0 && mShadowDrawable != null) {
      if (mScreenSide == STICK_TO_RIGHT) {
        mShadowDrawable.setBounds(0, 0, mShadowSize, getHeight());
      }
      if (mScreenSide == STICK_TO_TOP) {
        mShadowDrawable.setBounds(0, getHeight() - mShadowSize, getWidth(), getHeight());
      }
      if (mScreenSide == STICK_TO_LEFT) {
        mShadowDrawable.setBounds(getWidth() - mShadowSize, 0, getWidth(), getHeight());
      }
      if (mScreenSide == STICK_TO_BOTTOM) {
        mShadowDrawable.setBounds(0, 0, getWidth(), mShadowSize);
      }
      mShadowDrawable.drawToCanvas(canvas);
    }
  }

  private void adjustLayoutParams() {

    ComponentContainer.LayoutConfig baseParams = getLayoutConfig();

    if (baseParams instanceof ComponentContainer.LayoutConfig) {

      LayoutConfig layoutParams = (LayoutConfig) baseParams;

      setLayoutConfig(baseParams);

    } else if (baseParams instanceof DependentLayout.LayoutConfig) {

      DependentLayout.LayoutConfig layoutParams = (DependentLayout.LayoutConfig) baseParams;

      switch (mScreenSide) {
        case STICK_TO_BOTTOM:
          layoutParams.addRule(DependentLayout.LayoutConfig.ALIGN_PARENT_BOTTOM);
          break;
        case STICK_TO_LEFT:
          layoutParams.addRule(DependentLayout.LayoutConfig.ALIGN_PARENT_LEFT);
          break;
        case STICK_TO_RIGHT:
          layoutParams.addRule(DependentLayout.LayoutConfig.ALIGN_PARENT_RIGHT);
          break;
        case STICK_TO_TOP:
          layoutParams.addRule(DependentLayout.LayoutConfig.ALIGN_PARENT_TOP);
          break;
        default:
          break;
      }
    }

  }

  /**
   * Get the destination position based on the velocity
   */
  private int[] getDestScrollPosForState(int state) {

    int[] pos = new int[2];

    if (state == STATE_OPENED) {
      return pos;
    } else {

      int layerOffset = state == STATE_CLOSED ? mOffsetDistance : mPreviewOffsetDistance;

      switch (mScreenSide) {
        case STICK_TO_RIGHT:
          pos[0] = -getWidth() + layerOffset;
          break;
        case STICK_TO_LEFT:
          pos[0] = getWidth() - layerOffset;
          break;
        case STICK_TO_TOP:
          pos[1] = getHeight() - layerOffset;
          break;
        case STICK_TO_BOTTOM:
          pos[1] = -getHeight() + layerOffset;
          break;
        default:
          break;
      }

      return pos;
    }
  }

  public int getContentLeft() {
    return getLeft() + getPaddingLeft();
  }


  @Override
  public void onScrolled() {
    if (!scrollHelper.isFinished()) {
      if (scrollHelper.isOverScrolled()) {
        final int oldX = getScrollValue(AXIS_X);
        final int oldY = getScrollValue(AXIS_Y);
        final int x = scrollHelper.getCurrValue(AXIS_X);
        final int y = scrollHelper.getCurrValue(AXIS_Y);

        if (oldX != x || oldY != y) {
          scrollToAndNotify(x, y);
        }

        // Keep on drawing until the animation has finished.
        invalidate();
        return;
      }
    }
    // Done with scroll, clean up state.
    completeScroll();
  }


  /**
   * Handler interface for obtaining updates on the <code>SlidingLayer</code>'s state.
   * <code>OnInteractListener</code> allows for external
   * classes to be notified when the <code>SlidingLayer</code>
   * receives input to be opened or closed.
   */
  public interface OnInteractListener {

    /**
     * This method is called when an attempt is made to open the current <code>SlidingLayer</code>.
     * Note that because of animation, the <code>SlidingLayer</code> may not be visible yet.
     */
    void onOpen();

    /**
     * This method is called when an attempt is made to show the preview mode in the current
     * <code>SlidingLayer</code>. Note that because of animation,
     * the <code>SlidingLayer</code> may not be
     * visible yet.
     */
    void onShowPreview();

    /**
     * This method is called when an attempt
     * is made to close the current <code>SlidingLayer</code>. Note
     * that because of animation, the <code>SlidingLayer</code> may still be visible.
     */
    void onClose();

    /**
     * this method is executed after <code>onOpen()</code>, when the animation has finished.
     */
    void onOpened();

    /**
     * this method is executed after <code>onShowPreview()</code>, when the animation has finished.
     */
    void onPreviewShowed();

    /**
     * this method is executed after <code>onClose()</code>, when the animation has finished and the
     * <code>SlidingLayer</code> is
     * therefore no longer visible.
     */
    void onClosed();
  }

  private void notifyActionStartedForState(int state) {

    switch (state) {
      case STATE_CLOSED:
        mOnInteractListener.onClose();
        break;

      case STATE_PREVIEW:
        mOnInteractListener.onShowPreview();
        break;

      case STATE_OPENED:
        mOnInteractListener.onOpen();
        break;
      default:
        break;
    }
  }

  private void notifyActionFinished() {

    switch (mCurrentState) {
      case STATE_CLOSED:
        mOnInteractListener.onClosed();
        break;

      case STATE_PREVIEW:
        mOnInteractListener.onPreviewShowed();
        break;

      case STATE_OPENED:
        mOnInteractListener.onOpened();
        break;
      default:
        break;
    }
  }

  /**
   * Interface definition for a callback to be invoked when the layer has been scrolled.
   */
  public interface OnScrollListener {

    /**
     * Callback method to be invoked when the layer has been scrolled. This will be
     * called after the scroll has completed
     *
     * @param absoluteScroll The absolute scrolling delta relative to the position of the container
     */
    void onScroll(int absoluteScroll);
  }

  private void setLayerState(final int state, final boolean smoothAnimation, final boolean force,
                             final int velocityX, final int velocityY) {
    if (state == mCurrentState) {
      return;
    }

    if (smoothAnimation && state == 2) {
      smoothScrollTo(state);
    } else if (smoothAnimation && state == 0) {
      smoothScrollTo(state);
    }
    mCurrentState = state;
  }

  /**
   * Get the angles required for different layouts
   */
  private void setAngle() {
    if (transform == Transform_TO_ROTATION) {
      switch (mScreenSide) {
        case STICK_TO_RIGHT:
          angle = 5;
          break;
        case STICK_TO_LEFT:
          angle = -5;
          break;
        case STICK_TO_TOP:
          angle = -5;
          break;
        default:
          angle = 5;
          break;
      }
      animatorPropertyOne
          .rotate(angle);
    }
  }

  /**
   * Like {@link Component#scrollBy}, but scroll smoothly instead of immediately.
   *
   * @param velocity the velocity associated with a fling, if applicable. (0
   *                 otherwise)
   */
  void smoothScrollTo(int velocity) {
    int width = depend.getWidth();
    int height = depend.getHeight();
    setAngle();
    builder = null;
    builder = animatorGroup.build();
    if (velocity == 2) {
      chooseAnimationOut(width, height);
      builder.addAnimators(animatorPropertyOne).addAnimators(animatorProperty, animatorPropertyTwo);
      if (drag) {
        animatorGroup.setDuration(50);
      } else {
        animatorGroup.setDuration(200);
      }
      animatorGroup.start();
    } else {
      chooseAnimationReturn(width, height);
      animatorGroup.runParallel(animatorProperty, animatorPropertyTwo);
      if (drag) {
        animatorGroup.setDuration(50);
      } else {
        animatorGroup.setDuration(200);
      }
      animatorGroup.start();
    }
  }

  /**
   * Different animation effects are selected according to the conditions
   */
  private void chooseAnimationOut(int width, int height) {
    if (offsetEnable) {
      switch (mScreenSide) {
        case STICK_TO_RIGHT:
          animatorProperty
              .moveFromX(widthMax - changeOffset)
              .moveToX(widthMax - width);
          break;
        case STICK_TO_LEFT:
          animatorProperty
              .moveFromX(-width + changeOffset)
              .moveToX(0);
          break;
        case STICK_TO_TOP:
          animatorProperty
              .moveFromY(-height + changeOffset)
              .moveToY(-height * 0.3f);
          break;
        case STICK_TO_BOTTOM:
          animatorProperty
              .moveFromY(height - changeOffset)
              .moveToY(0);
          break;
        default:
          break;
      }
    } else {
      switch (mScreenSide) {
        case STICK_TO_RIGHT:
          animatorProperty
              .moveFromX(widthMax)
              .moveToX(widthMax - width);
          break;
        case STICK_TO_LEFT:
          animatorProperty
              .moveFromX(-width)
              .moveToX(0);
          break;
        case STICK_TO_TOP:
          animatorProperty
              .moveFromY(-height)
              .moveToY(-height * 0.3f);
          break;
        case STICK_TO_BOTTOM:
          animatorProperty
              .moveFromY(height)
              .moveToY(0);
          break;
        default:
          break;
      }
    }
    switch (transform) {
      case Transform_TO_ALPHA:
        animatorPropertyTwo
            .alphaFrom(0.1f).alpha(1.0f);
        break;
      case Transform_TO_ROTATION:
        animatorPropertyTwo
            .rotate(0);
        break;
      case Transform_TO_SLIDE:
        animatorPropertyTwo
            .scaleYFrom(0.9f).scaleY(1.0f)
            .scaleXFrom(0.85f).scaleX(1.0f);
        break;
      default:
        break;
    }


  }

  private void chooseAnimationReturn(int width, int height) {

    if (offsetEnable) {
      switch (mScreenSide) {
        case STICK_TO_RIGHT:
          animatorProperty
              .moveFromX(startX)
              .moveToX(widthMax - changeOffset);
          break;
        case STICK_TO_LEFT:
          animatorProperty
              .moveFromX(startX)
              .moveToX(-width + changeOffset);
          break;
        case STICK_TO_TOP:
          animatorProperty
              .moveFromY(startY)
              .moveToY(-height);
          break;
        case STICK_TO_BOTTOM:
          animatorProperty
              .moveFromY(startY)
              .moveToY(height - changeOffset);
          break;
        default:
          break;
      }
    } else {
      switch (mScreenSide) {
        case STICK_TO_RIGHT:
          animatorProperty
              .moveFromX(startX)
              .moveToX(widthMax);
          break;
        case STICK_TO_LEFT:
          animatorProperty
              .moveFromX(startX)
              .moveToX(-width);
          break;
        case STICK_TO_TOP:
          animatorProperty
              .moveFromY(startY)
              .moveToY(-height);
          break;
        case STICK_TO_BOTTOM:
          animatorProperty
              .moveFromY(startY)
              .moveToY(height);
          break;
        default:
          break;
      }
    }
    switch (transform) {
      case Transform_TO_ALPHA:
        animatorPropertyTwo
            .alphaFrom(0.8f).alpha(0.2f);
        break;
      case Transform_TO_ROTATION:
        animatorPropertyTwo
            .rotate(angle);
        break;
      case Transform_TO_SLIDE:
        animatorPropertyTwo
            .scaleYFrom(1.0f).scaleY(0.9f)
            .scaleXFrom(1.0f).scaleX(0.85f);
        break;
      default:
        break;
    }
  }
  public void setCurrentState(int state){
    mCurrentState=state;
  }

}
